package com.ruoyi.basedata.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruoyi.basedata.domain.MeterSheets;
import com.ruoyi.basedata.domain.TerminalsDb;
import com.ruoyi.basedata.domain.TerminalsXb;
import com.ruoyi.basedata.mapper.MeterSheetsMapper;
import com.ruoyi.basedata.mapper.TerminalsDbMapper;
import com.ruoyi.basedata.mapper.TerminalsXbMapper;
import com.ruoyi.basedata.service.IMeterSheetsService;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.text.Convert;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.domain.SysSheetUsers;
import com.ruoyi.system.mapper.SysDeptMapper;
import com.ruoyi.system.mapper.SysSheetUsersMapper;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigInteger;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 区域管理Service业务层处理
 *
 * @author gdqt
 * @date 2024-03-01
 */
@Service
public class MeterSheetsServiceImpl implements IMeterSheetsService {
    @Autowired
    private MeterSheetsMapper meterSheetsMapper;

    @Autowired
    private SysSheetUsersMapper sysSheetUsersMapper;
    @Autowired
    private SysDeptMapper sysDeptMapper;
    @Autowired
    private TerminalsXbMapper terminalsXbMapper;
    @Autowired
    private TerminalsDbMapper terminalsDbMapper;

    /**
     * 区域树类型-通用区域
     */
    private static final int TREE_TYPE_COMMON = 1;
    /**
     * 区域树类型-通用、大表区域
     */
    private static final int TREE_TYPE_DB = 2;
    /**
     * 区域树类型-户表专用区域
     */
    private static final int TREE_TYPE_XB = 3;
    /**
     * 查询区域管理
     *
     * @param id 区域管理主键
     * @return 区域管理
     */
    @Override
    public MeterSheets selectMeterSheetsById(Long id) {
        return meterSheetsMapper.selectMeterSheetsById(id);
    }

    /**
     * 查询区域管理列表
     *
     * @param meterSheets 区域管理
     * @return 区域管理
     */
    @Override
    public List<MeterSheets> selectMeterSheetsList(MeterSheets meterSheets) {
        return meterSheetsMapper.selectMeterSheetsList(meterSheets);
    }

    /**
     * 新增区域管理
     *
     * @param meterSheets 区域管理
     * @return 结果
     */
    @Override
    public int insertMeterSheets(MeterSheets meterSheets) {
        meterSheets.setCreateTime(DateUtils.getNowDate());
        return meterSheetsMapper.insertMeterSheets(meterSheets);
    }

    /**
     * 修改区域管理
     *
     * @param meterSheets 区域管理
     * @return 结果
     */
    @Override
    public int updateMeterSheets(MeterSheets meterSheets) {
        meterSheets.setUpdateTime(DateUtils.getNowDate());
        return meterSheetsMapper.updateMeterSheets(meterSheets);
    }

    /**
     * 批量删除区域管理
     *
     * @param ids 需要删除的区域管理主键
     * @return 结果
     */
    @Override
    public int deleteMeterSheetsByIds(Long[] ids) {
        return meterSheetsMapper.deleteMeterSheetsByIds(ids);
    }

    /**
     * 删除区域管理信息
     *
     * @param id 区域管理主键
     * @return 结果
     */
    @Override
    public int deleteMeterSheetsById(Long id) {
        return meterSheetsMapper.deleteMeterSheetsById(id);
    }

    @Override
    public List<MeterSheets> selectMeterSheetsBySheetsCode(String sheetsCode) {
        LambdaQueryWrapper<MeterSheets> queryWrapper = new LambdaQueryWrapper<>();
        if (StrUtil.isNotEmpty(sheetsCode)) {
            ArrayList<String> sheetsCodeList = CollUtil.toList(sheetsCode.split(","));
            queryWrapper.in(MeterSheets::getSheetsCode, sheetsCodeList);
        }
        queryWrapper.eq(MeterSheets::getDeviceType,1);
        return meterSheetsMapper.selectList(queryWrapper);
    }

    @Override
    public List<MeterSheets> getAreaTree(int treeType,String sheetsName,String sheetsCode, String sheetsAddr,String details, boolean showDeviceCount) {
        SysUser user = SecurityUtils.getLoginUser().getUser();
        List<Integer> sheetidList;
        List<MeterSheets> allMeterSheets;
        //当不是管理员时查询绑定的区域
        if (user.getSystemFlag() != Constants.SYS_FLAG_ADMIN){
            List<SysSheetUsers> sysSheetUsers = sysSheetUsersMapper.selectList(new LambdaQueryWrapper<SysSheetUsers>()
                    .eq(SysSheetUsers::getSysUserid, user.getUserId().intValue()));
            //假如该用户未绑定区域
            if (sysSheetUsers.size() == 0){
                return null;
            }
            sheetidList = sysSheetUsers.stream().map(SysSheetUsers::getSheetid).collect(Collectors.toList());
            allMeterSheets = meterSheetsMapper.selectList(new LambdaQueryWrapper<MeterSheets>()
                    .in(MeterSheets::getId, sheetidList)
                    .in(treeType == TREE_TYPE_DB,MeterSheets::getDeviceType,Arrays.asList(0,2))
                    .eq(treeType == TREE_TYPE_COMMON,MeterSheets::getDeviceType,0)
                    .eq(MeterSheets::getDelFlag,0));
            if ((treeType == TREE_TYPE_COMMON || treeType == TREE_TYPE_XB)){
                List<MeterSheets> collect = allMeterSheets.stream().filter(item -> item.getDeviceType() == 0).collect(Collectors.toList());
                for (MeterSheets item : collect) {
                    List<MeterSheets> community = meterSheetsMapper.selectList(new LambdaQueryWrapper<MeterSheets>()
                            .eq(MeterSheets::getDeviceType,1)
                            .eq(MeterSheets::getParentId, item.getId())
                            .eq(MeterSheets::getDelFlag,0));
                    allMeterSheets.addAll(community);
                }

            }
        }else {
            //是超级管理员就查全部
            allMeterSheets = meterSheetsMapper.selectList(new LambdaQueryWrapper<MeterSheets>()
                    .in(treeType == 2,MeterSheets::getDeviceType,Arrays.asList(0,2))
                    .in(treeType == 1,MeterSheets::getDeviceType,Arrays.asList(0,1))
                    .eq(MeterSheets::getDelFlag,0));
        }
        if (user.getSystemFlag() == Constants.SYS_FLAG_NORMAL_USER){
            List<MeterSheets> general = allMeterSheets.stream().filter(t -> t.getDeviceType() == 0).collect(Collectors.toList());
            List<MeterSheets> notGeneral = allMeterSheets.stream().filter(t -> t.getDeviceType() != 0 && (t.getDeviceType() == 2 || Objects.equals(t.getTenantId(), user.getTenantId()))).collect(Collectors.toList());
            general.addAll(notGeneral);
            allMeterSheets = general;
        }
        if (sheetsName != null){
            allMeterSheets = allMeterSheets.stream().filter( t -> t.getSheetsName() != null && t.getSheetsName().contains(sheetsName)).collect(Collectors.toList());
        }
        if (sheetsAddr != null){
            allMeterSheets = allMeterSheets.stream().filter( t -> t.getSheetsAddr() != null && t.getSheetsAddr().contains(sheetsAddr)).collect(Collectors.toList());
        }
        if (details != null){
            allMeterSheets = allMeterSheets.stream().filter( t -> t. getDetails() != null && t.getDetails().contains(details)).collect(Collectors.toList());
        }
        if (sheetsCode != null){
            String regex = "^" + sheetsCode + ".*";
            Pattern compiledPattern = Pattern.compile(regex);
            allMeterSheets= allMeterSheets.stream().filter(t -> {
                String code = t.getSheetsCode();
                Matcher matcher = compiledPattern.matcher(code);
                return matcher.find();
            }).collect(Collectors.toList());
        }
        SysDept dept = new SysDept();
        dept.setDelFlag("0");
        List<SysDept> allDepts = sysDeptMapper.selectDeptList(dept);
        for (MeterSheets sheets:allMeterSheets){
            for (SysDept sysDept:allDepts){
                if (StringUtils.isNotBlank(sheets.getTenantId())&&StringUtils.equals(sheets.getTenantId(),sysDept.getTenantId())){
                    sheets.setDeptName(sysDept.getDeptName());
                    break;
                }
            }
        }
        List<Long> allIds = allMeterSheets.stream().map(MeterSheets::getId).collect(Collectors.toList());
        List<MeterSheets> parentNode = allMeterSheets.stream().filter(item -> !allIds.contains(item.getParentId())).collect(Collectors.toList());
        setChildrenArea(parentNode,allMeterSheets);
        if (showDeviceCount) {
            List<MeterSheets> countBySheetsIdList;
            if (treeType == TREE_TYPE_COMMON || treeType == TREE_TYPE_XB) {
                countBySheetsIdList = terminalsXbMapper.selectCountBySheetsId();
            } else {
                countBySheetsIdList = terminalsDbMapper.selectCountBySheetsId();
            }
            Map<Long, Integer> countBySheetsId = countBySheetsIdList.stream().collect(Collectors.groupingBy(MeterSheets::getId, Collectors.summingInt(MeterSheets::getDeviceCount)));
            countAreaDevice(parentNode, countBySheetsId);
            return sortAreaTree(parentNode);
        }
        return parentNode;
    }

    @Override
    public List<MeterSheets> getAreaPermissionsByUserId(Long loginUserId) {
        List<SysSheetUsers> list = sysSheetUsersMapper.selectList(new LambdaQueryWrapper<SysSheetUsers>()
                .eq(SysSheetUsers::getSysUserid, loginUserId));
        List<Integer> collect = list.stream().map(SysSheetUsers::getSheetid).collect(Collectors.toList());
        return list.size() == 0 ? null : meterSheetsMapper.selectList(new LambdaQueryWrapper<MeterSheets>()
                .in(MeterSheets::getId, collect)
                .eq(MeterSheets::getDelFlag,0));
    }



    private void setCommunity(List<MeterSheets> parentList,List<MeterSheets> allMeterSheets){
        if (allMeterSheets != null && allMeterSheets.size() > 0){
            List<MeterSheets> collect = allMeterSheets.stream().filter(t -> t.getDeviceType() == 0).collect(Collectors.toList());
            for (MeterSheets item : collect) {
                List<MeterSheets> community = meterSheetsMapper.selectList(new LambdaQueryWrapper<MeterSheets>()
                        .in(MeterSheets::getDeviceType,Arrays.asList(0,1))
                        .eq(MeterSheets::getParentId, item.getId())
                        .eq(MeterSheets::getDelFlag,0));
                parentList.addAll(community);
                setChildrenArea(parentList,community);
            }
        }
    }

    private void setChildrenArea(List<MeterSheets> parentList,List<MeterSheets> allMeterSheets){
        if (parentList != null && parentList.size() > 0){
            parentList.forEach(meterSheets -> {
                List<MeterSheets> childrens = allMeterSheets.stream().filter(item -> item.getParentId().equals(meterSheets.getId())).collect(Collectors.toList());
                meterSheets.setChildren(childrens);
                setChildrenArea(childrens,allMeterSheets);
            });
        }
    }



    @Override
    @Transactional
    public void addMeterSheets(MeterSheets meterSheets) {
        List<MeterSheets> childList = meterSheetsMapper.selectList(new LambdaQueryWrapper<MeterSheets>()
                .eq(MeterSheets::getParentId, meterSheets.getParentId()));
        String newSheetCode = "";
        if (childList == null || childList.size() == 0){
            MeterSheets parentMeterSheets = meterSheetsMapper.selectMeterSheetsById(meterSheets.getParentId());
            newSheetCode = parentMeterSheets.getSheetsCode() + "001";
        }else {
            List<String> codeList = childList.stream().map(MeterSheets::getSheetsCode).collect(Collectors.toList());
            //不为空时就找出最大的areaCode+1
            BigInteger maxCode = BigInteger.valueOf(Long.MIN_VALUE);
            String maxCodeString = "";
            for(String areaCode : codeList){
                BigInteger l = new BigInteger(areaCode);
                if (l.compareTo(maxCode) > 0){
                    maxCode = l;
                    maxCodeString =  areaCode;
                }
            }
            newSheetCode = String.valueOf(maxCode.add(BigInteger.ONE));
            int length = newSheetCode.length();
            int zerosToAdd = maxCodeString.length()-length;
            for (int i = 0;i<zerosToAdd;i++){
                newSheetCode = "0" + newSheetCode;
            }
        }
        meterSheets.setSheetsCode(newSheetCode);
        meterSheetsMapper.insertMeterSheets(meterSheets);
        if (SecurityUtils.getLoginUser().getUser().getSystemFlag() != 0 && meterSheets.getDeviceType() != 1){
            SysSheetUsers sheetUsers = new SysSheetUsers();
            sheetUsers.setSheetid(meterSheets.getId().intValue());
            sheetUsers.setSysUserid(SecurityUtils.getUserId().intValue());
            sysSheetUsersMapper.insert(sheetUsers);
        }
    }

    private int countAreaDevice(List<MeterSheets> parentNode, Map<Long, Integer> countBySheetsId) {
        int deviceCount = 0;
        if (CollectionUtils.isNotEmpty(parentNode)) {
            for (MeterSheets sheets : parentNode) {
                sheets.setDeviceCount(MapUtils.getInteger(countBySheetsId, sheets.getId(), 0) + countAreaDevice(sheets.getChildren(), countBySheetsId));
                deviceCount += sheets.getDeviceCount();
            }
        }
        return deviceCount;
    }

    /**
     * 根据设备数量排序树节点
     *
     * @param treeNode 树节点
     */
    private List<MeterSheets> sortAreaTree(List<MeterSheets> treeNode) {
        if (CollectionUtils.isNotEmpty(treeNode)) {
            List<MeterSheets> sorted = treeNode.stream().sorted(Comparator.comparing(MeterSheets::getDeviceCount, Comparator.nullsLast(Comparator.reverseOrder()))).collect(Collectors.toList());
            for (MeterSheets sheets:sorted){
                sheets.setChildren(sortAreaTree(sheets.getChildren()));
            }
            return sorted;
        }
        return Collections.emptyList();
    }
}
